package crmdna.client;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.gson.Gson;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.common.Utils;
import crmdna.common.api.APIException;
import crmdna.common.api.APIResponse.Status;
import crmdna.user.UserEntity;

public class ClientTest {

  private final LocalServiceTestHelper helper = new LocalServiceTestHelper(
      new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());


  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    ObjectifyFilter.complete();
    helper.tearDown();
  }

  @Test
  public void createTest() {
    ClientEntity entity = Client.create("Isha");
    assertEquals("isha", entity.name);
    assertEquals("Isha", entity.displayName);

    entity = Client.safeGet(entity.name);
    // should not throw exception
    assertTrue(entity.name.equals("isha"));
    assertTrue(entity.displayName.equals("Isha"));


    // cannot create the same name again
    try {
      entity = Client.create("Isha");
      assertTrue(false);
    } catch (APIException ex) {
      assertTrue(ex.statusCode == Status.ERROR_RESOURCE_ALREADY_EXISTS);
    }

    // cannot create in different case
    try {
      entity = Client.create("iSHa");
      assertTrue(false);
    } catch (APIException ex) {
      assertTrue(ex.statusCode == Status.ERROR_RESOURCE_ALREADY_EXISTS);
    }

    // big name should get truncated
    entity = Client.create("Isha Foundation");
    System.out.println("entity: " + new Gson().toJson(entity));
    assertEquals("isha fou", entity.name);
    assertEquals("Isha Foundation", entity.displayName);

    // cannot create same name again
    try {
      entity = Client.create("Isha Foundation Yoga");
      assertTrue(false);
    } catch (APIException e) {
      assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, e.statusCode);
    }
  }

  @Test
  public void safeGetTest() {
    ClientEntity entity = Client.create("Isha");

    entity = Client.safeGet("isha");
    // should not throw exception
    assertTrue(entity.name.equals("isha"));
    assertTrue(entity.displayName.equals("Isha"));

    // exception for non existant client
    try {
      entity = Client.safeGet("nonexist"); // non existant
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    // exception when client is null
    try {
      entity = Client.safeGet(null); // non existant
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }
  }

  @Test
  public void getTest() {
    assertTrue(false);
  }

  @Test
  public void getEntitiesTest() {
    Client.create("isha");
    Client.create("barclays");

    ObjectifyFilter.complete();
    Map<String, ClientEntity> map = Client.getEntities(Utils.getSet("isha", "barclays", "dummy"));

    assertEquals(2, map.size());
    assertTrue(map.containsKey("isha"));
    assertTrue(map.containsKey("barclays"));
  }

  @Test
  public void updateDisplayName() {
    ClientEntity entity = Client.create("Isha");
    assertEquals("isha", entity.name);

    entity = Client.updateDisplayName("isha", "Isha Foundation");
    entity = Client.safeGet("isha");
    assertTrue(entity.name.equals("isha"));
    assertTrue(entity.displayName.equals("Isha Foundation"));
  }

  @Test
  public void ensureValidClientTest() {
    // throws exception is client does not exist
    try {
      Client.ensureValid("isha"); // non existant
      assertTrue(false);
    } catch (APIException ex) {
      assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
    }

    Client.create("isha");
    Client.ensureValid("isha");
    // no exception
  }

  @Test
  public void getAllTest() {
    List<ClientProp> all = Client.getAll();
    assertEquals(0, all.size());

    Client.create("Isha Foundation");
    Client.create("Barclays Capital");

    all = Client.getAll();
    assertEquals(2, all.size());

    // should be sorted by name
    assertEquals("barclays", all.get(0).name);
    assertEquals("Barclays Capital", all.get(0).displayName);
    assertEquals("isha fou", all.get(1).name);
    assertEquals("Isha Foundation", all.get(1).displayName);
  }

  @Test
  public void addUserTest() {
    ClientEntity entity = Client.create("isha");
    assertEquals("isha", entity.name);

    String email = "sai@ishafoundation.org";
    Client.addUser("isha", email);
    ObjectifyFilter.complete();

    assertEquals("isha", CrmDnaUser.getClients(email).first().name);

    List<UserEntity> users = Client.getAllUsers("isha");
    assertEquals(1, users.size());
    assertTrue(users.get(0).email.equals(email));

    String email2 = "sathyanarayanant@gmail.com";
    Client.addUser("isha", email2);
    Client.addUser("isha", email);
    ObjectifyFilter.complete();

    users = Client.getAllUsers("isha");
    assertEquals(2, users.size());
    assertEquals(email, users.get(0).email);
    assertEquals(email2, users.get(1).email);
  }

  @Test
  public void deleteUserTest() {
    ClientEntity entity = Client.create("isha");
    assertEquals("isha", entity.name);

    String email = "sathya.t@ishafoundation.org";
    Client.addUser("isha", email);
    ObjectifyFilter.complete();

    assertEquals("isha", CrmDnaUser.getClients(email).first().name);

    // now delete it
    Client.deleteUser("isha", email);
    ObjectifyFilter.complete();

    assertEquals(0, CrmDnaUser.getClients(email).size());

    List<UserEntity> users = Client.getAllUsers("isha");
    System.out.println("users: " + new Gson().toJson(users));
    assertEquals(0, users.size());

    // can delete the user again
    Client.deleteUser("isha", email); // no exception
  }

  @Test
  public void getAllUsersTest() {
    ClientEntity client = Client.create("isha");
    assertEquals("isha", client.name);

    Client.addUser("isha", "email2@email.com");
    Client.addUser("isha", "email3@email.com");
    Client.addUser("isha", "email1@email.com");
    ObjectifyFilter.complete();

    List<UserEntity> users = Client.getAllUsers("isha");
    assertEquals(3, users.size());
    List<UserEntity> list = new ArrayList<>();
    list.addAll(users);
    assertEquals("email1@email.com", list.get(0).email);
    assertEquals("email2@email.com", list.get(1).email);
    assertEquals("email3@email.com", list.get(2).email);
  }
}
